package com.jn.exam.webSocket.component;

import com.alibaba.fastjson.JSONObject;
import com.jn.exam.TransactionUtils;
import com.jn.exam.webSocket.entity.ExamStudentOnline;
import com.jn.exam.webSocket.entity.MessageResult;
import com.jn.exam.webSocket.entity.StudentConnection;
import com.jn.exam.webSocket.service.ExamService;
import com.jn.exam.webSocket.service.ExamStudentOnlineService;
import com.jn.exam.webSocket.service.WebSocketService;
import com.jn.exam.webSocket.utils.EncoderServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author 江南大学1033190417
 * @date 2022/3/4 19:25
 */
@ServerEndpoint(value = "/webSocket/web-socket-server/{singleId}", encoders = {EncoderServer.class})
@Component
@Slf4j
public class WebSocketServer {

    public static ConcurrentHashMap<String, Session> electricSocketMap = new ConcurrentHashMap<>();

    //解决无法注入问题
    private static ApplicationContext applicationContext;

    private AtomicInteger ati = new AtomicInteger();

    public static void setApplicationContext(ApplicationContext applicationContext) {
        WebSocketServer.applicationContext = applicationContext;
    }

    @OnOpen
    public void open(@PathParam("singleId") String singleId, Session session) {
        electricSocketMap.put(singleId, session);
        String[] split = singleId.split("-");
        if ("0".equals(split[2])) {//如果是学生建立了连接
            ExamService examService = applicationContext.getBean(ExamService.class);
            ExamStudentOnlineService examStudentOnlineService = applicationContext.getBean(ExamStudentOnlineService.class);
            TransactionUtils transactionUtils = applicationContext.getBean(TransactionUtils.class);
            TransactionStatus begin = null;
            try {
                begin = transactionUtils.begin();//开启事务
                StudentConnection connection = examService.getExamStudentConnectionTeaForFeign(split[1], split[0]);
                //更新学生参加考试状态
                StudentConnection studentConnection = new StudentConnection();
                studentConnection.setStudentId(split[0]).setExamId(split[1]).setIsAttended(0);
                if (connection.getFirstEnter()==null){
                    studentConnection.setFirstEnter(new Date());
                }
                boolean b = examService.updateExamStudentConnectionForFeign(studentConnection);
                //记录学生上线动作
                ExamStudentOnline examStudentOnline = new ExamStudentOnline();
                examStudentOnline.setOnline(true).setStudentId(split[0]).setExamId(split[1]);
                boolean save = examStudentOnlineService.save(examStudentOnline);
                if (b && save) {
                    transactionUtils.commit(begin);//事务提交
                    sendAll(new MessageResult(singleId, "1", 0));//给监考老师发消息
                }
            } catch (Exception e) {
                //手动回滚
                transactionUtils.rollback(begin);
            }
        } else if ("3".equals(split[2])) {//如果是老师阅卷的情况
            //将状态修改为正在阅卷的状态
            ExamService examService = applicationContext.getBean(ExamService.class);
            StudentConnection studentConnection = new StudentConnection();
            studentConnection.setIsMarked(0).setStudentId(split[0]).setExamId(split[1]);
            examService.updateExamStudentConnectionForFeign(studentConnection);
        }
        log.info("用户：{}建立连接", singleId);
    }

    @OnClose
    public void close(@PathParam("singleId") String singleId, Session session) {
        if (electricSocketMap.containsKey(singleId)) {
            String[] split = singleId.split("-");
            if ("0".equals(split[2])) {//如果学生断开了连接
                ExamService examService = applicationContext.getBean(ExamService.class);
                ExamStudentOnlineService examStudentOnlineService = applicationContext.getBean(ExamStudentOnlineService.class);
                TransactionUtils transactionUtils = applicationContext.getBean(TransactionUtils.class);
                TransactionStatus begin = null;
                try {
                    begin = transactionUtils.begin();//开启事务
                    //更新学生参加考试状态
                    StudentConnection studentConnection = new StudentConnection();
                    studentConnection.setStudentId(split[0]).setExamId(split[1]).setIsAttended(-1);
                    boolean b = examService.updateExamStudentConnectionForFeign(studentConnection);
                    //记录学生下线动作
                    ExamStudentOnline examStudentOnline = new ExamStudentOnline();
                    examStudentOnline.setOnline(false).setStudentId(split[0]).setExamId(split[1]);
                    boolean save = examStudentOnlineService.save(examStudentOnline);
                    if (b && save) {
                        transactionUtils.commit(begin);//事务提交
                        sendAll(new MessageResult(singleId, "0", 0));
                    }
                } catch (Exception e) {
                    //手动回滚
                    transactionUtils.rollback(begin);
                }
            } else if ("3".equals(split[2])) {//如果是老师阅卷的情况
                //将状态修改为正在阅卷的状态
                ExamService examService = applicationContext.getBean(ExamService.class);
                StudentConnection studentConnection = new StudentConnection();
                studentConnection.setIsMarked(-1).setStudentId(split[0]).setExamId(split[1]);
                examService.updateExamStudentConnectionForFeign(studentConnection);
            }
            electricSocketMap.remove(singleId);
            log.info("用户：{}断开连接", singleId);
        }
    }

    @OnMessage
    public void onMessage(@PathParam("singleId") String singleId, Session session, String message) {
        log.info("接收到：{}的消息：{}", singleId, message);
        MessageResult messageResult = JSONObject.parseObject(message, MessageResult.class);
        if (messageResult.getMsgType() == -1) {//如果是用户向服务器发送的心跳
            return;
        }
        singleId = messageResult.getSingleId();
        WebSocketService webSocketService = applicationContext.getBean(WebSocketService.class);
        if (messageResult.getMsgType() == 2) {//如果是老师发来的学生作弊的信息
            ExamService examService = applicationContext.getBean(ExamService.class);
            String[] split = singleId.split("-");
            String studentId = split[0];
            String examId = split[1];
            StudentConnection studentConnection = new StudentConnection();
            studentConnection.setStudentId(studentId).setExamId(examId).setIsCheated(true);
            examService.updateExamStudentConnectionForFeign(studentConnection);//将学生作弊信息更新到数据库
            //给所有监考老师发消息
            webSocketService.senAll(messageResult);
        }
        if (electricSocketMap.containsKey(singleId)) {//如果当前服务器端有这个用户，就直接发送消息
            session = electricSocketMap.get(singleId);
            sendMsg(session, messageResult);
        } else {//如果没有，通过消息队列广播
            webSocketService.send(singleId, messageResult);
        }
    }

    @OnError
    public void error(Session session, Throwable error) {
        error.printStackTrace();
        System.out.println("发生错误");
    }


    public static void sendMsg(Session session, MessageResult message) {
        try {
            session.getBasicRemote().sendObject(message);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //群发消息
    public void sendAll(MessageResult message) {
        WebSocketService webSocketService = applicationContext.getBean(WebSocketService.class);
        webSocketService.senAll(message);
    }





}
